﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Linq;
using Client_Server_Interface;
using BTM_Client_DBwork.Exceptions;
using NHibernate.Transaction;

namespace BTM_Client_DBwork
{
    internal class DBhelper : IDisposable
    {
        private const string ConString = "Data Source=client.db;Version=3;UTF8Encoding=True;Foreign Keys=True;";
        private ISessionFactory _sessionFactory;

        public DBhelper()
        {
            Connect();
        }

        private void Connect()
        {
            Fluently.Configure()
                    .Database(SQLiteConfiguration.Standard.ConnectionString(ConString))
                    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Options>())
                    .ExposeConfiguration(CreateSchema)
                    .BuildConfiguration();
            _sessionFactory = CreateSessionFactory();
            using (_sessionFactory.OpenSession())
            {
                
            }
        }

        public ISession Session
        {
            get { return _sessionFactory.OpenSession(); }
        }

        private static void CreateSchema(Configuration cfg)
        {
            //var schemaExport = new SchemaExport(cfg);
            //schemaExport.Execute(false, true, false);
            var schemaUpdate = new SchemaUpdate(cfg);
            schemaUpdate.Execute(false, true);
            
        }

        private ISessionFactory CreateSessionFactory()
        {
            return
                Fluently.Configure()
                        .Database(SQLiteConfiguration.Standard.ConnectionString(ConString))
                        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Options>())
                        .BuildSessionFactory();
        }

        public void Dispose()
        {
            if (!_sessionFactory.IsClosed)
                _sessionFactory.Close();
        }
    }

    public class DBwork : IMonitoringClientDBwork
    {
        private readonly DBhelper _helper;

        public DBwork()
        {
            _helper = new DBhelper();
        }

        public bool SetParameter(string paramName, string paramValue)
        {
            using (var s = _helper.Session)
            {
                bool tryAnother = false;
                try
                {
                    using (var tx = s.BeginTransaction())
                    {                        
                        var item = s.Query<Options>().Single(p => p.Name == paramName);
                        item.OptionValue = paramValue;
                        tx.Commit();
                    }
                    return true;
                }
                catch (InvalidOperationException)
                {
                    tryAnother = true;                    
                }
                if (tryAnother)
                {
                    try
                    {
                        var opt = new Options { Name = paramName, OptionValue = paramValue };
                        s.Save(opt);
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
                return false;
            }
        }

        public string GetParameterValue(string paramName)
        {
            string retValue;
            using (var s = _helper.Session)
            {
                var item =  s.Query<Options>().Single(o => o.Name == paramName);
                retValue = item.OptionValue;
            }
            return retValue;
        }

        public Dictionary<string, string> GetParametersList()
        {
            throw new NotImplementedException();
        }

        public void SetLibraryName(string deviceName, string libraryName)
        {
            using (var s = _helper.Session)
            {
                try
                {
                    using (var tx = s.BeginTransaction())
                    {
                        var item = s.Query<DeviceLibraries>().Single(p => p.Name == deviceName);
                        item.LibraryName = libraryName;
                        tx.Commit();
                    }
                }
                catch (InvalidOperationException)
                {
                    var opt = new DeviceLibraries { Name = deviceName, LibraryName = libraryName };
                    s.Save(opt);
                }
            }
        }

        public string GetLibraryName(string deviceName)
        {
            string retValue;
            using (var s = _helper.Session)
            {
                var item = s.Query<DeviceLibraries>().Single(o => o.Name == deviceName);
                retValue = item.LibraryName;
            }
            return retValue;
        }

        public void SetTreeItemTag(string itemName, string tag)
        {
            using (var s = _helper.Session)
            {
                try
                {
                    using (var tx = s.BeginTransaction())
                    {
                        var item = s.Query<TreeItemTags>().Single(p => p.Name == itemName);
                        item.Tag = tag;
                        tx.Commit();
                    }
                }
                catch (InvalidOperationException)
                {
                    var opt = new TreeItemTags { Name = itemName, Tag = tag };
                    s.Save(opt);
                }
            }
        }

        public string GetTreeItemTag(string itemName)
        {
            string retValue;
            using (var s = _helper.Session)
            {
                var item = s.Query<TreeItemTags>().Single(o => o.Name == itemName);
                retValue = item.Tag;
            }
            return retValue;
        }

        public void SetMapMarkerPosition(string markerName, double lat, double lng)
        {
            using (var s = _helper.Session)
            {
                try
                {
                    using (var tx = s.BeginTransaction())
                    {
                        var item = s.Query<MapMarkerPositions>().Single(p => p.Name == markerName);
                        item.PositionLat = lat;
                        item.PositionLng = lng;
                        tx.Commit();
                    }
                }
                catch (InvalidOperationException)
                {
                    var opt = new MapMarkerPositions {Name = markerName, PositionLat = lat, PositionLng = lng};
                    s.Save(opt);
                }
            }
        }

        public void RemoveMapMarkerPosition(string markerName)
        {
            using (var s = _helper.Session)
            {
                try
                {
                    using (var tx = s.BeginTransaction())
                    {
                        var items = s.Query<MapMarkerPositions>().ToList();
                        var item = items.SingleOrDefault(x => x.Name == markerName);
                        if(item == null)
                            return;
                        s.Delete(item);
                        tx.Commit();
                    }
                }
                catch (InvalidOperationException)
                {
                    
                }
            }
        }

        /// <summary>
        /// Получает из БД координаты маркера (Lat, Lng).
        /// </summary>
        /// <param name="markerName">Название маркера.</param>
        /// <returns>Координаты маркера (Lat, Lng).</returns>
        public KeyValuePair<double, double> GetMapMarkerPosition(string markerName)
        {
            KeyValuePair<double, double> retValue;
            using (var s = _helper.Session)
            {
                var item = s.Query<MapMarkerPositions>().Single(o => o.Name == markerName);
                retValue = new KeyValuePair<double, double>(item.PositionLat, item.PositionLng);
            }
            return retValue;
        }
    }

}
